#include <assert.h>
#include "memcheck.h"
#include "CCReactor.h"
#include "CCSocketHandler.h"
#include <poll.h>
#include <map>
#include <vector>
//#include <sys/ioctl.h>

extern CMemPool*	_memPool;

vector<CCSocketHandler*> delVector;
void CheckDelVector()
{
	CCSocketHandler* pHandler = NULL;
	for (int i = 0; i < delVector.size(); i++)
	{
		pHandler = delVector[i];
		delete pHandler;
	}
	delVector.clear();
}

CCSocketHandler::CCSocketHandler():
	_stage(CONN_IDLE),
	_r(_memPool),
	_w(_memPool),
	_id(0), 
	_type(0),
	_property_ptr(NULL),
	_property_u32(-1),
	_isDel(false),
	m_tick(0),
	_decode(NULL)
{
	m_dprot = DATA_PROTOCOL_UNKNOWN;
	m_wshandshake = false;
}

CCSocketHandler::~CCSocketHandler()
{
	_w.skip( _w.data_len() );
	_r.skip( _r.data_len() );

	m_tick = 0;
	if(_decode)
		DELETE(_decode);
}
 
int CCSocketHandler::Init()
{
	if( _decode == NULL){
		this->_decode = this->CreateDecoder();
	}
	assert(this->_decode);
	CPollerObject::EnableInput ();
	return 0;
}

int  CCSocketHandler::RecvData(char buff[], int buff_size, int time_out)
{

	struct pollfd fds;
	fds.fd = this->netfd;
	fds.events = POLLIN;
	while (true)
	{
		int ret = poll(&fds, 1, time_out * 1000);
		if (ret < 0)
		{
			if (-1 == ret && EINTR == errno)
				continue;

			return ret;
		}
		else if (0 == ret)
			return ret; //time out

		if (POLLIN & fds.revents)
		{
			while (true)
			{
				int recv_len = ::recv(fds.fd, buff, buff_size, 0);
				if (-1 == recv_len)
				{
					if (errno == EINTR)
					{
						continue;
					}
					log_error("recv failed from fd[%d], errno[%s]", netfd, strerror(errno));
					return -1;
				}
				else if (0 == recv_len)
				{
					DisableInput();
					_stage = CONN_DISCONNECT;
					log_error("connection disconnect  fd[%d], ip[%s], port[%d]", netfd, _sip.c_str(), _port);


					handle_close();
					return  -1;
				}
				
				return recv_len;
			}
		}

		return -1;
	}

}

int CCSocketHandler::InputNotify(void)
{
	int stage = handle_input();
	switch (stage)
	{
		case CONN_DATA_ERROR:
			log_error("input decode error, netfd[%d], stage[%d]", netfd, stage);
			handle_close();
			return POLLER_COMPLETE;

		case CONN_DISCONNECT:
			log_notice("input disconnect by user, netfd[%d], stage[%d]", netfd, stage);
			handle_close();
			return POLLER_COMPLETE;

		case CONN_DATA_RECVING:
		case CONN_IDLE:
		case CONN_RECV_DONE:
			CheckDelVector();
			return POLLER_SUCC;

		case CONN_FATAL_ERROR:
			log_error("input fatal error, netfd[%d], stage[%d]", netfd, stage);
			handle_close();
			return POLLER_COMPLETE;

		default:
			log_error("input unknow status, netfd[%d], stage[%d]", netfd, stage);
			handle_close();
			return POLLER_COMPLETE;
		}
}

int CCSocketHandler::OutputNotify ()
{
    int stage = handle_output();
    switch (stage)
	{
		case CONN_SEND_DONE:
			log_debug ("reponse data completed, netfd[%d]", netfd);
		    return POLLER_COMPLETE;
		case CONN_DATA_SENDING:
			log_debug ("reponse data sending, netfd[%d]", netfd);
			return POLLER_SUCC;
		case CONN_FATAL_ERROR:
			handle_close();
			return POLLER_COMPLETE;
		default:
			log_error("response data to client failed, netfd[%d],stage[%d]", netfd, stage);
			handle_close();
			return POLLER_COMPLETE;
	}
}

int CCSocketHandler::HangupNotify ()
{
	handle_close();
	return POLLER_COMPLETE;
}
 
int CCSocketHandler::handle_input()
{
	int	ret = 0 ;
	int	packet_len = 0 ;
	int	curr_recv_len   = 0;
	char	curr_recv_buf[MAX_WEB_RECV_LEN] = {'\0'};

// 	int len = 0;
// 	ioctl(netfd, FIONREAD, &len);
// 	log_notice("fd,%d,recvbuflen,%d", netfd, len);

	curr_recv_len = ::recv (netfd, curr_recv_buf, MAX_WEB_RECV_LEN, 0);
	//log_debug ("*STEP: receiving data, length[%d]", curr_recv_len);
 
	if(-1 == curr_recv_len)//������������
	{
		if (errno != EAGAIN && errno != EINTR && errno != EINPROGRESS)
		{
			DisableInput();
			_stage = CONN_FATAL_ERROR;
			log_warning ("recv failed from fd[%d], msg[%s]", netfd, strerror(errno));
		}
		else
			_stage = CONN_DATA_RECVING;
	}
	else if( 0 == curr_recv_len )//�ͻ��˹ر�����
	{
		DisableInput ();
		_stage = CONN_DISCONNECT;
		log_notice ("connection disconnect by user fd[%d], msg[%s]", netfd, strerror(errno));
	}
	else
	{
		_r.append(curr_recv_buf, curr_recv_len);
		while(_r.data_len() > 0)
		{
			packet_len = this->_decode->ParsePacket(_r.data(), _r.data_len(), this, &m_wsrPack);
			if(packet_len == -1) //���ݴ���
			{
				DisableInput ();
				_stage = CONN_DATA_ERROR;
				break ;
			}
			else if(packet_len == 0) //��ͷ�����꣬�ȴ�����
			{
				_stage = CONN_DATA_RECVING;
				break;
			}
			else //������������ inputRet=���������� 
			{
				if(DATA_PROTOCOL_WEBSOCKET == getDataProtocol())
				{
					if (isWshandshake())
					{
						if(1 == m_wsrPack.get_fin())
						{
							if (m_wsrPack.entire_data_len() > 0)//websocket payload长度可能为0
							{
								ret = this->OnPacketComplete(m_wsrPack.data(), m_wsrPack.entire_data_len());
							}
							//log_debug("websocket fram data,fin:%d, opcode:%d, mask:%d, payload len:%d", m_wsrPack.get_fin(), m_wsrPack.get_opcode(), m_wsrPack.get_mask(), m_wsrPack.entire_data_len());
							m_wsrPack.clear();
						}
					}
					else
					{
						m_wsrPack.pack_handshake_rsp();
						Send(m_wsrPack.get_handshakersp().data(), m_wsrPack.get_handshakersp().size());
						m_wsrPack.clear();
						setWshandshake(true);
						//log_debug("websocket handshak");
					}	
				}
				else
				    ret = this->OnPacketComplete(_r.data(), packet_len);

				if( ret < 0 )           
				{ 
					_stage = CONN_FATAL_ERROR; 
					break;
				}
				_stage = CONN_RECV_DONE; 
				_r.skip(packet_len);
			}
		}
	}
 
	return _stage;
}

int CCSocketHandler::handle_output()
{
	log_debug("*STEP: send data, len:[%d] netfd[%d]", _w.data_len(), netfd);	
	if (_w.data_len() != 0)
	{		
		int ret = ::send (netfd, _w.data(), _w.data_len(), 0);
		if(-1 == ret)
		{
			if(errno == EINTR || errno == EAGAIN || errno == EINPROGRESS)
			{
				log_warning("sending,INTR|EAGAIN|EINPROGRESS,errno:[%d]", errno);
				EnableOutput ();
				ApplyEvents ();
				_stage = CONN_DATA_SENDING;
				return _stage;
			}
		
			log_error("send_err , sending package to client failed, ret[%d], errno:[%d], fd[%d] ", ret, errno, netfd);
			DisableInput ();
			DisableOutput ();
			ApplyEvents ();
			_stage = CONN_FATAL_ERROR;
			return _stage;
		}

		if(ret == (int)_w.data_len())
		{
			log_debug("send complete, send len=[%d]",ret);
			DisableOutput();
			ApplyEvents ();
			_w.skip(ret);	
			_stage = CONN_SEND_DONE;
			return _stage;
		}
		else if (ret < (int)_w.data_len())
		{
			log_debug("had sent part of data, send len=[%d]",ret);
			EnableOutput ();
			ApplyEvents ();
			_w.skip(ret);
			_stage = CONN_DATA_SENDING;
			return _stage;
		}
	}

	DisableOutput();
	ApplyEvents ();	
	_stage = CONN_FATAL_ERROR;
	log_debug("send process failure");
	return _stage;
}

int CCSocketHandler::Send(const char * buff, int len)
{
	if(len>0)
	{
		if (GetReconnectFlag() == true && netfd<=0)
		{
			Connect();
		}
		const char* sendbuff = buff;
		int sendlen = len;

		if(this->_w.data_len()==0)
		{
			int ret = ::send (netfd,buff, len, 0);
			if(-1 == ret)
			{
				if(errno == EINTR || errno == EAGAIN || errno == EINPROGRESS)
				{
					log_warning("sending,INTR|EAGAIN|EINPROGRESS,errno:[%d], fd[%d]", errno, netfd);
					this->_w.append(sendbuff, sendlen);
					EnableOutput ();
					ApplyEvents ();
					_stage = CONN_DATA_SENDING;
					return 0;
				}
				else
				{
					log_error("send_err sending package to client failed, ret[%d], errno:[%d], fd[%d]", ret, errno, netfd);
					//_stage = CONN_FATAL_ERROR;
					//handle_close();
					this->_w.append(sendbuff, sendlen);
					EnableOutput();
					ApplyEvents();
					_stage = CONN_DATA_SENDING;
					return -1;
				}
			}
			else if(ret<len)
			{
				sendbuff += ret;
				sendlen -=  ret;
				this->_w.append(sendbuff, sendlen);
				EnableOutput ();
				ApplyEvents ();
				_stage = CONN_DATA_SENDING;
				log_debug("had sent part of data, send len=[%d]",ret);
				return ret;
			}
			else if(ret==len)
			{
				//log_debug("send complete, send len=[%d]",len);
				_stage = CONN_SEND_DONE;
				return ret;
			}
		}
		else
		{
			this->_w.append(sendbuff, sendlen);
			if( handle_output() ==CONN_FATAL_ERROR )
			{
				//handle_close();
				log_error("sending package to client failed, fd[%d]", netfd);
				EnableOutput();
				ApplyEvents();
				_stage = CONN_DATA_SENDING;
				return -1;
			}
			else
				return len;
		}
	}
	return len;
}

int CCSocketHandler::OnPacketComplete(const char* data, int len)
{
	return 0;
}	

int CCSocketHandler::OnClose()
{
	log_debug("client  OnClose: fd=[%d] ip=[%d:%d]",this->GetNetfd(),this->GetIP(),this->GetPort());
	return 0;
}

int CCSocketHandler::OnConnected()
{
	log_debug("client  OnConnected: fd=[%d] ip=[%d:%d]",this->GetNetfd(),this->GetIP(),this->GetPort());
	return 0;
}

void CCSocketHandler::Reset()
{
	log_debug("reset socket handler, fd=%d, ", netfd);
	_w.skip( _w.data_len() );
	_r.skip( _r.data_len() );
	DisableInput();
	DisableOutput();
	//ApplyEvents();
	CPollerObject::DetachPoller();
	if(netfd > 0)
	{
		::close(netfd);
	}
	netfd  = -1;
	_stage = CONN_IDLE;
	return;
}

int CCSocketHandler::handle_close()
{
	int ret = this->OnClose();
	if (0 == ret)
	{
		//delete this;
		Destroy();
	}
	else if (ret < 0)
	{
		Reset();
	}
	else
	{//ret>0, handle by uplayer
		//do nothing
	}
	
	return 0;
}

void CCSocketHandler::Destroy()
{
	log_debug("Destroy  fd=%d, ", netfd);
	_id = 0;
	_type = 0;
	_property_ptr = NULL;
	_property_u32 = -1;
	Reset();
	if (!_isDel)
	{
		_isDel = true;
		delVector.push_back(this);
	}
	//delete this;
}

int CCSocketHandler::Connect()
{
	int ret = -1;
	if (_stage == CONN_IDLE)
	{
		ret = CNet::tcp_connect(&netfd, GetSIP().c_str(), GetPort(), 0);
	}
	else
	{
		if (netfd < 0)
		{
			ret = CNet::tcp_connect(&netfd, GetSIP().c_str(), GetPort(), 0);
		}
		else
		{
			ret = 0;
		}
	}
	
	if(ret <0)
	{
		if (ret == SOCKET_CREATE_FAILED)
		{
			log_error("*STEP: helper create socket failed, errno[%d], msg[%s]", errno, strerror(errno));
			handle_close();
			return -1;
		}

		if(errno != EINPROGRESS)
		{
			log_error("*STEP: PROXY connect to logic failed, errno[%d], msg[%s]", errno , strerror(errno));
			handle_close();
			return -1;
		}

		_stage = CONN_CONNECTING;
		
		log_debug("*STEP: PROXY connecting to logic, unix fd[%d]", netfd);
		goto exit;
	}
	else
	{
		_stage = CONN_CONNECTED;
	}
exit:
	ret = CCReactor::Instance()->AttachPoller(this);
	this->OnConnected();
	return ret;
}
dataProtocol CCSocketHandler::getDataProtocol(void)
{
	return m_dprot;
}
void CCSocketHandler::setDataProtocol(dataProtocol prot)
{
	m_dprot = prot;
}
bool CCSocketHandler::isWshandshake(void)
{
	return m_wshandshake;
}
void CCSocketHandler::setWshandshake(bool handshake)
{
	m_wshandshake = handshake;
}